
#include "ScriptingTypes.h"

namespace GTA
{
	Vector3::Vector3()
	{
		Base = new Scripting::Vector3();
	}

	Vector3::Vector3(float x, float y, float z)
	{
		Base = new Scripting::Vector3();
		Base->X=x;
		Base->Y=y;
		Base->Z=z;
	}

	Vector3^ Vector3::Cross(Vector3^ other)
	{
		Vector3D v3dthis = Vector3D(this->X,this->Y,this->Z);
		Vector3D v3dother = Vector3D(other->X,other->Y,other->Z);
		Vector3D v3dret = Vector3D::CrossProduct(v3dthis,v3dother);
		Vector3^ ret = gcnew Vector3(v3dret.X,v3dret.Y,v3dret.Z);
		return ret;
	}

	Vector3^ Vector3::Normalize()
	{
		Vector3D v3dthis = Vector3D(this->X,this->Y,this->Z);
		v3dthis.Normalize();
		Vector3^ ret = gcnew Vector3(v3dthis.X,v3dthis.Y,v3dthis.Z);
		return ret;
	}

	double Vector3::Dot(Vector3^ other)
	{
		Vector3D v3dthis = Vector3D(this->X,this->Y,this->Z);
		Vector3D v3dother = Vector3D(other->X,other->Y,other->Z);
		double ret = Vector3D::DotProduct(v3dthis,v3dother);
		return ret;
	}


	
     /// <summary>
    ///		Gets the shortest arc quaternion to rotate this vector to the destination vector. 
    /// </summary>
    /// <remarks>
    ///		Don't call this if you think the dest vector can be close to the inverse
    ///		of this vector, since then ANY axis of rotation is ok.
    ///	</remarks>
	GTA::Quaternion^ Vector3::GetRotationTo(Vector3^ destination)
	{ // http://www.koders.com/csharp/fidCA8558A72AF7D3E654FDAFA402A168B8BC23C22A.aspx
		// Based on Stan Melax's article in Game Programming Gems
		Quaternion^ q = gcnew Quaternion();

		Vector3 ^v0 = gcnew Vector3(this->X, this->Y, this->Z);
		Vector3 ^v1 = destination;

		// normalize both vectors 
		v0 = v0->Normalize();
		v1 = v1->Normalize();

		// get the cross product of the vectors
		Vector3 ^c = v0->Cross(v1);

		// If the cross product approaches zero, we get unstable because ANY axis will do
		// when v0 == -v1
		float d = v0->Dot(v1);

		// If dot == 1, vectors are the same
		if (d >= 1.0f)
		{
			return gcnew Quaternion(0.0F,0.0F,0.0F,1.0F);
			//return Quaternion::Identity;
		}

		float s = System::Math::Sqrt((1 + d) * 2);
		float inverse = 1 / s;

		q->X = c->X * inverse;
		q->Y = c->Y * inverse;
		q->Z = c->Z * inverse;
		q->W = s * 0.5f;

		return q;
	}



	// --------------------- Quaternion ----------------------------

	Quaternion::Quaternion()
	{
		Base = gcnew System::Windows::Media::Media3D::Quaternion(0.0,0.0,0.0,0.0);
	}

	Quaternion::Quaternion(f32 w,f32 x,f32 y,f32 z)
	{
		Base = gcnew System::Windows::Media::Media3D::Quaternion((double)w,(double)x,(double)y,(double)z);
	}


};

/*
//converts a Quaternion to Euler angles (X = pitch, Y = yaw, Z = roll)
public static Vector3^ Quaternion::QuaternionToEuler(Quaternion rotation)
{
    Vector3^ rotationaxes = new Vector3();

	Vector3D^ forward = Vector3D::Transform(Vector3::Forward, rotation);
	Vector3D^ up = Vector3D::Transform(Vector3.Up, rotation);
    rotationaxes = AngleTo(new Vector3(), forward);
    if (rotationaxes.X == MathHelper.PiOver2)
    {
        rotationaxes.Y = ArcTanAngle(up.Z, up.X);
        rotationaxes.Z = 0;
    }
    else if (rotationaxes.X == -MathHelper.PiOver2)
    {
        rotationaxes.Y = ArcTanAngle(-up.Z, -up.X);
        rotationaxes.Z = 0;
    }
    else
    {
        up = Vector3.Transform(up, Matrix.CreateRotationY(-rotationaxes.Y));
        up = Vector3.Transform(up, Matrix.CreateRotationX(-rotationaxes.X));
        rotationaxes.Z = ArcTanAngle(up.Y, -up.X);
    }
    return rotationaxes;          
}
*/